package com.shqyang.yexplorer;

import android.content.Intent;
import android.media.MediaScannerConnection;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnItemClickListener;
import com.chad.library.adapter.base.listener.OnItemLongClickListener;
import com.shqyang.yexplorer.adapter.FileAdapter;
import com.shqyang.yexplorer.adapter.RouteAdapter;
import com.shqyang.yexplorer.base.BaseFragment;
import com.shqyang.yexplorer.manager.ExplorerManager;
import com.shqyang.yexplorer.util.FileUtils;
import com.shqyang.yexplorer.util.LogManager;
import com.shqyang.yexplorer.util.NetUtils;
import com.shqyang.yexplorer.util.PermissionUtilsKt;
import com.shqyang.yexplorer.util.PxUtils;
import com.shqyang.yexplorer.util.StringUtil;
import com.shqyang.yexplorer.widget.DeleteDialog;
import com.shqyang.yexplorer.widget.EditDialog;
import com.shqyang.yexplorer.widget.MyEditTextButtonDialog;
import com.shqyang.yexplorer.widget.NormalDialog;
import com.shqyang.yexplorer.widget.OperateDialog;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;

/**
 * Created by swsbty on 2021/04/17
 */
public class ExplorerFragment extends BaseFragment {

    private final String TAG = getClass().getName();

    private LinearLayoutManager mExplorerMgr;
    private RecyclerView mRouteRv;
    private RecyclerView mExplorerRv;
    private TextView mEmptyTv;

    private EditDialog mEditDialog;

    private FileClickAction mClickAction;

    private RouteAdapter mRouteAdapter;
    private FileAdapter mFileAdapter;
    private List<File> mFileList;
    private String mRootPath;
    private Stack<File> mRecentList;
    private Stack<Integer> mRecentPositionStack;
    private boolean isShowRouteBar = true;
    private boolean isShowHiddenFile = true;

    private boolean mHasPermission = false;

    public ExplorerFragment(String rootPath) {
        this(rootPath, true);
    }

    public ExplorerFragment(String rootPath, boolean isShowRouteBar) {
        mRootPath = rootPath;
        this.isShowRouteBar = isShowRouteBar;
        ExplorerManager.initialize(this);
    }

    public boolean isShowHiddenFile() {
        return isShowHiddenFile;
    }

    public void setShowHiddenFile(boolean showHiddenFile) {
        isShowHiddenFile = showHiddenFile;
    }

    public int getFileListSize() {
        return mFileList.size();
    }

    public void setClickAction(FileClickAction clickAction) {
        mClickAction = clickAction;
    }

    /**
     * check all files
     */
    public void checkAll() {
        mFileAdapter.checkAll();
    }

    /**
     * set explorer root path
     * @param rootPath  explorer root path
     */
    private void setRootPath(String rootPath) {
        if (!mHasPermission) {
            Log.i(TAG, "setRootPath: no permission");
            return;
        }
        File file = new File(rootPath);
        if (!file.exists() || !file.isDirectory()) {
            Toast.makeText(mContext, R.string.rootPathError, Toast.LENGTH_SHORT).show();
            return;
        }
        mRecentList.push(file);
        File[] files = file.listFiles();
        if (files == null) {
            Toast.makeText(mContext, R.string.rootPathError, Toast.LENGTH_SHORT).show();
            return;
        }
        if (mFileList.size() > 0) {
            mFileList.clear();
        }
        mFileList.addAll(Arrays.asList(files));
        if (!isShowHiddenFile) {
            FileUtils.removeHiddenFileInList(mFileList);
        }
        FileUtils.sortFileByName(mFileList);
        notifyDataSetChanged();
    }

    /**
     * check if file list is empty, show empty textView if empty
     */
    private void checkEmpty() {
        if (mFileList.size() == 0) {
            mEmptyTv.setVisibility(View.VISIBLE);
        } else {
            mEmptyTv.setVisibility(View.GONE);
        }
    }

    /**
     * refresh route recyclerView and adapter
     */
    private void refreshRoute() {
        mRouteAdapter.notifyDataSetChanged();
        mRouteRv.scrollToPosition(mRecentList.size() - 1);
    }

    /**
     * refresh explorer recyclerView and adapter
     * @param file directory
     */
    private void refreshExplorer(File file) {
        if (!file.exists() || !file.isDirectory()) {
            return;
        }
        File[] files = file.listFiles();
        if (files == null) {
            return;
        }
        if (mFileList.size() > 0) {
            mFileList.clear();
        }
        mFileList.addAll(Arrays.asList(files));
        if (!isShowHiddenFile) {
            FileUtils.removeHiddenFileInList(mFileList);
        }
        FileUtils.sortFileByName(mFileList);
        notifyDataSetChanged();
    }

    public void hideRouteBar() {
        mRouteRv.setVisibility(View.GONE);
    }

    public void hideEmptyNotice() {
        mEmptyTv.setVisibility(View.GONE);
    }

    public void showRouteBar() {
        mRouteRv.setVisibility(View.VISIBLE);
    }

    @Override
    protected int layoutId() {
        return R.layout.yexplorer_fragment;
    }

    @Override
    public void initView() {
        mEditDialog = new EditDialog(mContext);
        mHasPermission = PermissionUtilsKt.hasReadFilePermission(requireActivity());
        mRouteRv = mRootView.findViewById(R.id.route_rv);
        mRouteRv.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));
        mRecentList = new Stack<>();
        mRecentPositionStack = new Stack<>();
        mRouteAdapter = new RouteAdapter(mRecentList);
        mRouteRv.setAdapter(mRouteAdapter);
        mExplorerRv = mRootView.findViewById(R.id.explorer_rv);
        mExplorerMgr = new LinearLayoutManager(mContext);
        mExplorerRv.setLayoutManager(mExplorerMgr);
        mExplorerRv.setItemViewCacheSize(0);
        mExplorerRv.getRecycledViewPool().setMaxRecycledViews(0, 0);
        mFileList = new ArrayList<>();
        mFileAdapter = new FileAdapter(mFileList);
        mExplorerRv.setAdapter(mFileAdapter);
        mEmptyTv = mRootView.findViewById(R.id.notice_tv);
        if (!isShowRouteBar) {
            hideRouteBar();
        }
    }

    /**
     * cancel check mode
     */
    public void cancelCheckMode() {
        mFileAdapter.setCheckMode(false);
    }

    @Override
    public void initEvent() {
        mEditDialog.setCancelClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                exitCheckMode();
            }
        });
        mEditDialog.setSelectAllClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mFileAdapter.checkAll();
                int size = getCheckedSize();
                refreshEditDialog(size);
                mClickAction.checkChange(size);
                mEditDialog.setSelectSizeText(size);
            }
        });
        mEditDialog.setQrCodeClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String filePath = getCheckedFilePath();
                OperateDialog dialog = new OperateDialog(mContext);
                dialog.createQrCode(filePath, NetUtils.getLocalIP(mContext), HarukaConfig.Deliver_Port);
                dialog.show();
            }
        });
        mEditDialog.setMoreCore(new EditDialog.MoreCore() {
            @Override
            public void open() {
                File file = mFileAdapter.getCheckedFile();
                mClickAction.openInApp(file);
                exitCheckMode();
            }

            @Override
            public void share() {
                File file = mFileAdapter.getCheckedFile();
                System.out.println("日志：" + Environment.getExternalStorageDirectory());
                Intent shareIntent = new Intent();
                shareIntent.setAction(Intent.ACTION_SEND);
                shareIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(mContext, "tech.haruka.fileProvider", file));
                shareIntent.setType("*/*");
                shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                System.out.println("日志：" + FileProvider.getUriForFile(mContext, "tech.haruka.fileProvider", file));
                //切记需要使用Intent.createChooser，否则会出现别样的应用选择框，您可以试试
                shareIntent = Intent.createChooser(shareIntent, "选择一个以分享文件");
                mContext.startActivity(shareIntent);
            }

            @Override
            public void rename() {
                File file = mFileAdapter.getCheckedFile();
                final MyEditTextButtonDialog renameDialog = new MyEditTextButtonDialog(mContext);
                renameDialog.getEditText().setHint("文件/文件夹名称");
                renameDialog.getEditText().setText(file.getName());
                renameDialog.getButton().setText("确定");
                renameDialog.getButton().setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        String newName = renameDialog.getEditText().getText().toString();
                        if (newName.trim().length() == 0) {
                            return;
                        }
                        boolean r = FileUtils.renameFile(file, newName);
                        Toast.makeText(mContext, r ? "修改成功" : "当前目录下已存在同名文件/文件夹", Toast.LENGTH_SHORT).show();
                        renameDialog.dismiss();
                        refreshUI();
                    }
                });
                renameDialog.show();
            }

            @Override
            public void showPath() {
                String path = getCheckedFilePath();
                exitCheckMode();
                final NormalDialog dialog = new NormalDialog(mContext);
                dialog.getNoButton().setText("关闭");
                dialog.getYesButton().setText("复制");
                dialog.setText(path).setYesClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        StringUtil.setClipData(mContext, path);
                        Toast.makeText(mContext, "已复制", Toast.LENGTH_SHORT).show();
                        dialog.dismiss();
                    }
                }).show();
            }
        });
        mEditDialog.setMoreClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String path = getCheckedFilePath();
                if (path == null) {
                    Toast.makeText(mContext, "无法获取文件路径", Toast.LENGTH_SHORT).show();
                    return;
                }
                File file = new File(path);
                boolean isShowShareButton = true;
                if (file.isDirectory()) {
                    isShowShareButton = false;
                }
                mEditDialog.showMorePopupMenu(isShowShareButton);
            }
        });
        mEditDialog.setMoveClickListener((v) -> {
            mClickAction.move(getCheckedFilePathList());
            exitCheckMode();
        });
        mEditDialog.setDeleteClickListener((v -> {
            int size = getCheckedSize();
            if (size == 0) {
                Toast.makeText(mContext, "请勾选需要删除的内容", Toast.LENGTH_SHORT).show();
                return;
            }
            final DeleteDialog dialog = new DeleteDialog(mContext);
            dialog.setFilePath(size);
            dialog.getDelete().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    List<File> files = getCheckedFileList();
                    Set<String> deletedFilePaths = new HashSet<>();
                    boolean isSuccess = FileUtils.deleteFile(files.toArray(new File[0]), deletedFilePaths);
                    dialog.dismiss();
                    if (!isSuccess) {
                        Toast.makeText(mContext, "删除失败", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    MediaScannerConnection.scanFile(mContext, deletedFilePaths.toArray(new String[0]), null, null);
                    refreshUI();
                    Toast.makeText(mContext, "已删除", Toast.LENGTH_SHORT).show();
                }
            });
            dialog.show();
        }));
        mRouteAdapter.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
                if (mFileAdapter.isCheckMode()) {
                    exitCheckMode();
                }
                int t = mRecentList.size() - position - 1;
                while (t > 0) {
                    mRecentList.pop();
                    t--;
                }
                File file = mRecentList.get(position);
                refreshRoute();
                refreshExplorer(file);
                scrollToPosition();
            }
        });
        mFileAdapter.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
                if (mFileAdapter.isCheckMode()) {
                    mFileAdapter.check(position);
                    int size = getCheckedSize();
                    mClickAction.checkChange(size);
                    refreshEditDialog(size);
                    return;
                }
                File file = mFileList.get(position);
                if (mRouteRv.getVisibility() == View.VISIBLE && file.isDirectory()) {
                    mRecentList.push(file);
                    mRecentPositionStack.push(mExplorerMgr.findFirstVisibleItemPosition());
                    Log.i(TAG, "onItemClick: position stack push " + mExplorerMgr.findFirstVisibleItemPosition());
                    refreshRoute();
                    refreshExplorer(file);
                } else {
                    mClickAction.openFile(file);
                }
            }
        });
        mFileAdapter.setOnItemLongClickListener(new OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(@NonNull BaseQuickAdapter adapter, @NonNull View view, int position) {
                enterCheckMode(position);
                mClickAction.checkChange(1);
                return false;
            }
        });
    }

    /**
     * refresh edit dialog ui
     * @param size checked file size
     */
    private void refreshEditDialog(int size) {
        mEditDialog.refreshSelectToolBar(size, getCheckedFilePath());// 显示底部多选工具栏
        mEditDialog.setSelectSizeText(size);
    }

    private String getCheckedFilePath() {
        File file = mFileAdapter.getCheckedFile();
        if (file == null) {
            return null;
        }
        return file.getPath();
    }

    /**
     * get size of checked files
     * @return
     */
    public int getCheckedSize() {
        return mFileAdapter.getCheckedSize();
    }

    /**
     * explorer scroll to position
     */
    private void scrollToPosition() {
        if (mRecentPositionStack.isEmpty()) {
            return;
        }
        Integer position = mRecentPositionStack.pop();
        mExplorerMgr.scrollToPositionWithOffset(position, 0);
        Log.i(TAG, "scrollToPosition: " + position);
    }

    @Override
    public void onResume() {
        super.onResume();
        refreshUI();
    }

    public void refreshUI() {
        if (getCurrentDirectory() == null) {
            return;
        }
        refreshExplorer(getCurrentDirectory());
        refreshRoute();
        exitCheckMode();
        checkEmpty();
    }

    public File getCurrentDirectory() {
        if (mRecentList.isEmpty()) {
            return null;
        }
        return mRecentList.lastElement();
    }

    /**
     * get checked file list
     * @return checked file list
     */
    public List<File> getCheckedFileList() {
        if (!mFileAdapter.isCheckMode() || mFileList.size() == 0) {
            return null;
        }
        boolean[] checkArr = mFileAdapter.getCheckedArray();
        List<File> checkedFileList = new ArrayList<>();
        for (int i = 0;i < checkArr.length;i++) {
            if (!checkArr[i]) {
                continue;
            }
            checkedFileList.add(mFileList.get(i));
        }
        return checkedFileList;
    }

    /**
     * get checked file list
     * @return checked file list
     */
    public ArrayList<String> getCheckedFilePathList() {
        if (!mFileAdapter.isCheckMode() || mFileList.size() == 0) {
            return null;
        }
        boolean[] checkArr = mFileAdapter.getCheckedArray();
        ArrayList<String> checkedFileList = new ArrayList<>();
        for (int i = 0;i < checkArr.length;i++) {
            if (!checkArr[i]) {
                continue;
            }
            checkedFileList.add(mFileList.get(i).getPath());
        }
        return checkedFileList;
    }

    /**
     * back to previous directory
     * @return false if no previous directory
     */
    public boolean back2previous() {
        if (mFileAdapter.isCheckMode()) {
            exitCheckMode();
            return true;
        }
        if (mRecentList.size() == 1) {
            return false;
        }
        mRecentList.pop();
        refreshRoute();
        File file = mRecentList.get(mRecentList.size() - 1);
        refreshExplorer(file);
        scrollToPosition();
        return true;
    }

    /**
     * exit check mode
     */
    public void exitCheckMode() {
        if (!mFileAdapter.isCheckMode()) {
            return;
        }
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mExplorerRv.getLayoutParams();
        params.bottomMargin = PxUtils.dip2px(mContext, 0);
        mExplorerRv.setLayoutParams(params);
        mFileAdapter.setCheckMode(false);
        mEditDialog.dismiss();
    }

    /**
     * enter check mode
     * @param position
     */
    public void enterCheckMode(int position) {
        mFileAdapter.setCheckMode(true, position);
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mExplorerRv.getLayoutParams();
        params.bottomMargin = PxUtils.dip2px(mContext, 80);
        mExplorerRv.setLayoutParams(params);
        mClickAction.checkChange(1);
        mClickAction.enterCheckMode();
        mEditDialog.show();
        refreshEditDialog(getCheckedSize());
    }

    @Override
    public void loadData(boolean isRefresh) {
        if (isRefresh) {
            mFileList.clear();
        }
        setRootPath(mRootPath);
    }

    public void clearList() {
        if (mFileAdapter.isCheckMode()) {
            LogManager.d("is check mode! can not clea list");
            return;
        }
        mFileList.clear();
        mFileAdapter.notifyDataSetChanged();
    }

    public void addToList(File file) {
        if (mFileAdapter.isCheckMode()) {
            LogManager.d("is check mode! can not add file");
            return;
        }
        mFileList.add(file);
        notifyDataSetChanged();
    }

    public void notifyDataSetChanged() {
        checkEmpty();
        mFileAdapter.notifyDataSetChanged();
    }

    public interface FileClickAction {
        void openInApp(File file);
        void openFile(File file);
        void enterCheckMode();
        void checkChange(int checkSize);
        void move(ArrayList<String> checkedFilePathList);
    }
}
